##############################################################################
# white_board.py
#
# A common drawing board for everyone on the server. Each player gets their
# own surface, and additional surfaces are laid one on top of the other. It
# uses the 'pic' flag for its server interface.
##############################################################################

import bgl, widget, zlib

import pygame
from pygame.locals import *

# A whiteboard is a shared drawing board that sends pictures over the
# network.
class WhiteBoard(widget.Widget):
    def __init__(self, control):
        widget.Widget.__init__(self)
        self.control = control
        
        self.size = (500,400)
        
        self.back = pygame.Surface( self.size )
        self.back.fill( (255,255,255) )
        
        self.my_surf = pygame.Surface( self.size ).convert_alpha()
        self.clean( self.my_surf )
        
        self.rect = pygame.Rect( (30,30),self.size )
        
        self.layers = {}
        
        self.brush = ( 3, (0,0,0) )
        self.last_pos = None
        self.held = False
        self.countdown = -1
        
    # Make a surface clean and transparent.
    def clean(self, surface):
        w,h = surface.get_size()
        for i in range(0,w):
            for j in range(0,h):
                c = surface.get_at( (i,j) )
                if c[3] != 0:
                    surface.set_at( (i,j), (255,255,255,0) )
    
    # Update the system. If this widget should get data from the server,
    # best to put a reference to the server in here so we can access it.
    def update(self):
        data = self.control.get("pic")
        for d in data:
            try:
                self.dirty = True
                ind = d.find("_")
                pic = d[ind+1:]
                num = d[:ind]
                if num not in self.layers:
                    self.layers[num]=pygame.Surface(self.size).convert_alpha()
                self.clean( self.layers[num] )
                s = zlib.decompress(pic)
                x = pygame.image.fromstring(s, self.size, "RGBA")
                self.layers[num].blit(x, (0,0))
            except:
                pass
        if self.held:
            self.held = False
            self.countdown = 50
        else:
            self.last_pos = None
        
        if self.countdown >= 0:
            self.countdown -= 1
        if self.countdown == 0:
            d = zlib.compress( pygame.image.tostring(self.my_surf, "RGBA") )
            self.control.send( "pic"+d )
    
    # Parse the event queue from the perspective of the widget.
    def parse_events(self, events):
        keys = pygame.key.get_pressed()
        pos = pygame.mouse.get_pos()
        mkeys = pygame.mouse.get_pressed()
        
        x = pos[0] - self.rect.topleft[0]
        y = pos[1] - self.rect.topleft[1]
        rpos = x,y
        
        for event in events:
			# A key has been pressed
            if event.type == KEYDOWN:
                self.dirty = True
				# Change to Eraser
                if event.key == K_e:
                    s,c = self.brush
                    self.brush = (s, None)
				# Change to brush
                if event.key == K_b:
                    s,c = self.brush
                    self.brush = (s, (0,0,0))
				# Clear whiteboard
                if event.key == K_c:
                    self.clean( self.my_surf )
                    self.countdown = 50
				# Increase brush size (by 1)
                if event.key == K_EQUALS:
                    s,c = self.brush
                    self.brush = (s+1, c)
				# Decrease brush size (by 1)
                if event.key == K_MINUS:
                    s,c = self.brush
                    if s > 1:
                        self.brush = (s-1, c)
        
		# Connect new line to previous end
        if keys[K_LSHIFT] or keys[K_RSHIFT]:
            self.held = True
		# Left-Mouse Button is pressed, so draw
        if mkeys[0]:
            self.doodle( rpos )
    
    # Draw on the whiteboard with your current brush.
    def doodle(self, pos):
        s,c = self.brush
        self.dirty = True
        
		# If c (color) is None, it is an eraser
        if c == None:
            self.erase( pos, s )
            return
        
		# Remember the previous position
        if self.last_pos == None:
            self.last_pos = pos
        
		# Draw the new line
        pygame.draw.line( self.my_surf, c, self.last_pos, pos, s )
        self.held = True
        self.last_pos = pos
        
    # Erases the stuff off of the whiteboard.
    def erase(self, pos, sz):
		# Get the size of the surface
        w,h = self.my_surf.get_size()
        x,y = pos
		# Everything with given range, set to white
        for i in range(-sz, sz):
            for j in range(-sz, sz):
                cx, cy = x+i, y+j
                if cx >= 0 and cx < w and cy >= 0 and cy < h:
                    self.my_surf.set_at( (cx,cy), (255,255,255,0) )
    
    # Draw the whiteboard in the drawing window.
    def draw(self, target):
        target.blit( self.back, self.rect )
        for x in self.layers:
            target.blit( self.layers[x], self.rect )
        target.blit( self.my_surf, self.rect )
